// ==========================================================
// top_i2c_probe.v  修复版：斜纹网格无滚动
// 关键修复：
// 1. 命令和数据分开发送（不在同一事务中混合）
// 2. 每页数据在同一个I2C DATA事务中连续发送128字节
// 3. 正确的事务流程：CMD->STOP->CMD->STOP->DATA->STOP
// ==========================================================
module top_i2c_probe #(
    parameter integer CLK_HZ     = 50_000_000,
    parameter integer I2C_HZ     = 50_000,
    parameter integer COLS       = 128,
    parameter integer ROWS       = 64,
    parameter integer STRIPE_LG2 = 3,
    parameter integer COL_OFFSET = 0  // SH1106=2, SSD1306=0
)(
    input  wire clk,
    input  wire rst_n,
    inout  wire I2C_SCL,
    inout  wire I2C_SDA,
    output wire led_nack
);

    // ---------- 开漏驱动 ----------
    reg scl_oe, sda_oe;
    assign I2C_SCL = scl_oe ? 1'b0 : 1'bz;
    assign I2C_SDA = sda_oe ? 1'b0 : 1'bz;
    wire sda_i = I2C_SDA;

    // ---------- 时基生成 ----------
    localparam integer DIV = (CLK_HZ / (I2C_HZ * 2));
    reg [31:0] divcnt;
    reg en;
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            divcnt <= 0;
            en <= 1'b0;
        end else begin
            if(divcnt == DIV-1) begin
                divcnt <= 0;
                en <= 1'b1;
            end else begin
                divcnt <= divcnt + 1;
                en <= 1'b0;
            end
        end
    end

    // ---------- 初始化ROM ----------
    localparam integer ROM_LEN = 13;
    reg [7:0] rom [0:ROM_LEN-1];
    initial begin
        rom[ 0] = 8'h00;  // Control: command
        rom[ 1] = 8'hAE;  // Display OFF
        rom[ 2] = 8'hD5;  // Set clock
        rom[ 3] = 8'h80;
        rom[ 4] = 8'hA8;  // Set multiplex
        rom[ 5] = 8'h3F;  // 64 rows
        rom[ 6] = 8'hD3;  // Set offset
        rom[ 7] = 8'h00;
        rom[ 8] = 8'h40;  // Start line
        rom[ 9] = 8'h8D;  // Charge pump
        rom[10] = 8'h14;
        rom[11] = 8'hA6;  // Normal display
        rom[12] = 8'hAF;  // Display ON
    end

    // ---------- 状态机定义 ----------
    localparam [5:0]
        S_IDLE       = 6'd0,
        S_IDLE_HOLD  = 6'd1,
        S_START      = 6'd2,
        S_ADDR_L     = 6'd3,
        S_ADDR_H     = 6'd4,
        S_ADDR_NXT   = 6'd5,
        S_ADDR_ACK_L = 6'd6,
        S_ADDR_ACK_H = 6'd7,
        S_DATA_L     = 6'd8,
        S_DATA_H     = 6'd9,
        S_DATA_NXT   = 6'd10,
        S_DATA_ACK_L = 6'd11,
        S_DATA_ACK_H = 6'd12,
        S_STOP_L     = 6'd13,
        S_STOP_H     = 6'd14,
        S_DONE       = 6'd15;

    // 工作阶段
    localparam [2:0]
        PHASE_INIT     = 3'd0,  // 初始化
        PHASE_SET_PAGE = 3'd1,  // 设置页地址
        PHASE_SET_COL  = 3'd2,  // 设置列地址
        PHASE_DATA     = 3'd3,  // 发送数据
        PHASE_FINISH   = 3'd4;  // 完成

    localparam integer PAGES = ROWS / 8;
    localparam integer MASK = (1 << STRIPE_LG2) - 1;

    reg [5:0] st;
    reg [2:0] phase;
    reg [2:0] bitcnt;
    reg [7:0] shreg;
    reg [3:0] byte_idx;
    reg       ack_seen;
    reg       addr_ok;
    reg       tried_alt;
    reg [6:0] addr7;
    reg [2:0] page;
    reg [7:0] col;
    reg [1:0] cmd_idx;  // 命令字节索引

    assign led_nack = ~ack_seen;

    // ---------- 斜纹网格数据生成 ----------
    function [7:0] gen_pattern_byte;
        input [7:0] col_in;
        input [2:0] page_in;
        integer i;
        reg [7:0] x, y, sum, diff;
        begin
            gen_pattern_byte = 8'h00;
            for(i = 0; i < 8; i = i + 1) begin
                x = col_in & MASK[7:0];
                y = ({page_in, 3'd0} + i[7:0]) & MASK[7:0];
                sum = (x + y) & MASK[7:0];
                diff = (x - y) & MASK[7:0];
                if((sum == 0) || (diff == 0))
                    gen_pattern_byte[i] = 1'b1;
            end
        end
    endfunction

    // ---------- 主状态机 ----------
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            st <= S_IDLE;
            phase <= PHASE_INIT;
            scl_oe <= 1'b0;
            sda_oe <= 1'b0;
            bitcnt <= 3'd7;
            shreg <= 8'h00;
            byte_idx <= 4'd0;
            ack_seen <= 1'b0;
            addr_ok <= 1'b0;
            tried_alt <= 1'b0;
            addr7 <= 7'h3C;
            page <= 3'd0;
            col <= 8'd0;
            cmd_idx <= 2'd0;
        end else if(en) begin
            case(st)
                // ========== 总线空闲 ==========
                S_IDLE: begin
                    scl_oe <= 1'b0;
                    sda_oe <= 1'b0;
                    st <= S_IDLE_HOLD;
                end

                S_IDLE_HOLD: begin
                    scl_oe <= 1'b0;
                    sda_oe <= 1'b0;
                    bitcnt <= 3'd7;
                    addr_ok <= 1'b0;
                    shreg <= {addr7, 1'b0};
                    st <= S_START;
                end

                // ========== START条件 ==========
                S_START: begin
                    scl_oe <= 1'b0;
                    sda_oe <= 1'b1;
                    st <= S_ADDR_L;
                end

                // ========== 发送地址 ==========
                S_ADDR_L: begin
                    scl_oe <= 1'b1;
                    sda_oe <= shreg[7] ? 1'b0 : 1'b1;
                    st <= S_ADDR_H;
                end

                S_ADDR_H: begin
                    scl_oe <= 1'b0;
                    st <= S_ADDR_NXT;
                end

                S_ADDR_NXT: begin
                    if(bitcnt != 3'd0) begin
                        shreg <= {shreg[6:0], 1'b0};
                        bitcnt <= bitcnt - 1'b1;
                        st <= S_ADDR_L;
                    end else begin
                        st <= S_ADDR_ACK_L;
                    end
                end

                // ========== 地址ACK ==========
                S_ADDR_ACK_L: begin
                    scl_oe <= 1'b1;
                    sda_oe <= 1'b0;
                    st <= S_ADDR_ACK_H;
                end

                S_ADDR_ACK_H: begin
                    scl_oe <= 1'b0;
                    if(sda_i == 1'b0) begin
                        ack_seen <= 1'b1;
                        addr_ok <= 1'b1;
                        bitcnt <= 3'd7;

                        // 根据阶段准备数据
                        case(phase)
                            PHASE_INIT: begin
                                byte_idx <= 4'd0;
                                shreg <= rom[0];
                            end
                            PHASE_SET_PAGE: begin
                                cmd_idx <= 2'd0;
                                shreg <= 8'h00;  // 控制字节：命令
                            end
                            PHASE_SET_COL: begin
                                cmd_idx <= 2'd0;
                                shreg <= 8'h00;  // 控制字节：命令
                            end
                            PHASE_DATA: begin
                                col <= 8'd0;
                                shreg <= 8'h40;  // 控制字节：数据
                            end
                            default: shreg <= 8'h00;
                        endcase
                        st <= S_DATA_L;
                    end else begin
                        addr_ok <= 1'b0;
                        st <= S_STOP_L;
                    end
                end

                // ========== 发送数据 ==========
                S_DATA_L: begin
                    scl_oe <= 1'b1;
                    sda_oe <= shreg[7] ? 1'b0 : 1'b1;
                    st <= S_DATA_H;
                end

                S_DATA_H: begin
                    scl_oe <= 1'b0;
                    st <= S_DATA_NXT;
                end

                S_DATA_NXT: begin
                    if(bitcnt != 3'd0) begin
                        shreg <= {shreg[6:0], 1'b0};
                        bitcnt <= bitcnt - 1'b1;
                        st <= S_DATA_L;
                    end else begin
                        st <= S_DATA_ACK_L;
                    end
                end

                // ========== 数据ACK ==========
                S_DATA_ACK_L: begin
                    scl_oe <= 1'b1;
                    sda_oe <= 1'b0;
                    st <= S_DATA_ACK_H;
                end

                S_DATA_ACK_H: begin
                    scl_oe <= 1'b0;
                    if(sda_i == 1'b0) ack_seen <= 1'b1;
                    bitcnt <= 3'd7;

                    case(phase)
                        // ========== 初始化阶段 ==========
                        PHASE_INIT: begin
                            if(byte_idx < ROM_LEN - 1) begin
                                byte_idx <= byte_idx + 1'b1;
                                shreg <= rom[byte_idx + 1'b1];
                                st <= S_DATA_L;
                            end else begin
                                // 初始化完成，开始第一页
                                phase <= PHASE_SET_PAGE;
                                page <= 3'd0;
                                st <= S_STOP_L;
                            end
                        end

                        // ========== 设置页地址 ==========
                        PHASE_SET_PAGE: begin
                            if(cmd_idx == 2'd0) begin
                                // 发送页地址命令
                                cmd_idx <= 2'd1;
                                shreg <= 8'hB0 | {5'b0, page};
                                st <= S_DATA_L;
                            end else begin
                                // 页地址设置完成
                                phase <= PHASE_SET_COL;
                                st <= S_STOP_L;
                            end
                        end

                        // ========== 设置列地址 ==========
                        PHASE_SET_COL: begin
                            case(cmd_idx)
                                2'd0: begin
                                    cmd_idx <= 2'd1;
                                    shreg <= 8'h00 | (COL_OFFSET[3:0]);  // 列地址低4位
                                    st <= S_DATA_L;
                                end
                                2'd1: begin
                                    cmd_idx <= 2'd2;
                                    shreg <= 8'h10 | (COL_OFFSET[7:4]);  // 列地址高4位
                                    st <= S_DATA_L;
                                end
                                default: begin
                                    // 列地址设置完成
                                    phase <= PHASE_DATA;
                                    st <= S_STOP_L;
                                end
                            endcase
                        end

                        // ========== 发送显示数据 ==========
                        PHASE_DATA: begin
                            if(col < COLS) begin
                                col <= col + 1'b1;
                                shreg <= gen_pattern_byte(col, page);
                                st <= S_DATA_L;
                            end else begin
                                // 当前页完成
                                if(page < PAGES - 1) begin
                                    page <= page + 1'b1;
                                    phase <= PHASE_SET_PAGE;
                                end else begin
                                    phase <= PHASE_FINISH;
                                end
                                st <= S_STOP_L;
                            end
                        end

                        default: st <= S_STOP_L;
                    endcase
                end

                // ========== STOP条件 ==========
                S_STOP_L: begin
                    scl_oe <= 1'b1;
                    sda_oe <= 1'b1;
                    st <= S_STOP_H;
                end

                S_STOP_H: begin
                    scl_oe <= 1'b0;
                    sda_oe <= 1'b0;

                    if(!addr_ok && !tried_alt) begin
                        tried_alt <= 1'b1;
                        addr7 <= 7'h3D;
                        st <= S_IDLE;
                    end else if(phase == PHASE_FINISH) begin
                        st <= S_DONE;
                    end else begin
                        st <= S_IDLE;
                    end
                end

                // ========== 完成 ==========
                S_DONE: begin
                    scl_oe <= 1'b0;
                    sda_oe <= 1'b0;
                    // 保持空闲或循环刷新
                end

                default: st <= S_IDLE;
            endcase
        end
    end
endmodule